package com.rickpan.service;

import com.rickpan.entity.TeamEncryptionKey;
import com.rickpan.repository.TeamEncryptionKeyRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Optional;

/**
 * 加密服务 - 负责团队密钥管理和加密解密操作
 * 
 * @author RickPan Team
 * @version 1.0
 * @since 2025-07-19
 */
@Slf4j
@Service
public class EncryptionService {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int GCM_IV_LENGTH = 12;
    private static final int GCM_TAG_LENGTH = 16;
    private static final int AES_KEY_LENGTH = 256;

    @Autowired
    private TeamEncryptionKeyRepository teamEncryptionKeyRepository;

    @Autowired
    private TeamMemberService teamMemberService;

    @Value("${app.encryption.master-key:RickPan2025SecureMasterKey!@#$%^&*()1234567890}")
    private String masterKeyString;

    /**
     * 为团队生成新的加密密钥
     * 
     * @param teamId 团队ID
     * @param createdBy 创建者用户ID
     * @return 生成的密钥ID
     */
    public Long generateTeamKey(Long teamId, Long createdBy) {
        try {
            log.info("🔑 开始为团队生成加密密钥: teamId={}, createdBy={}", teamId, createdBy);

            // 1. 生成256位AES密钥
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
            keyGenerator.init(AES_KEY_LENGTH);
            SecretKey secretKey = keyGenerator.generateKey();
            String teamKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());

            // 2. 用主密钥加密团队密钥
            String encryptedTeamKey = encryptWithMasterKey(teamKey);

            // 3. 获取下一个密钥版本号
            int nextVersion = getNextKeyVersion(teamId);

            // 4. 保存到数据库
            TeamEncryptionKey keyEntity = TeamEncryptionKey.builder()
                    .teamId(teamId)
                    .keyVersion(nextVersion)
                    .encryptedKey(encryptedTeamKey)
                    .algorithm("AES-256-GCM")
                    .isActive(true)
                    .createdBy(createdBy)
                    .build();

            TeamEncryptionKey savedKey = teamEncryptionKeyRepository.save(keyEntity);

            log.info("✅ 团队密钥生成成功: teamId={}, keyId={}, version={}", 
                    teamId, savedKey.getId(), nextVersion);

            return savedKey.getId();

        } catch (Exception e) {
            log.error("❌ 团队密钥生成失败: teamId={}", teamId, e);
            throw new RuntimeException("团队密钥生成失败", e);
        }
    }

    /**
     * 获取团队的活跃密钥
     * 
     * @param teamId 团队ID
     * @param userId 请求用户ID（用于权限验证）
     * @return 解密后的团队密钥
     */
    public String getTeamKey(Long teamId, Long userId) {
        try {
            log.debug("🔍 获取团队密钥: teamId={}, userId={}", teamId, userId);

            // 1. 验证用户权限
            if (!teamMemberService.isTeamMember(teamId, userId)) {
                log.warn("⚠️ 用户无权限访问团队密钥: teamId={}, userId={}", teamId, userId);
                throw new SecurityException("无权限访问团队密钥");
            }
            
            // 2. 查找活跃的团队密钥
            Optional<TeamEncryptionKey> keyEntity = teamEncryptionKeyRepository
                    .findByTeamIdAndIsActive(teamId, true);

            if (keyEntity.isEmpty()) {
                log.warn("⚠️ 团队密钥不存在: teamId={}", teamId);
                throw new RuntimeException("团队密钥不存在，请联系管理员");
            }

            // 3. 解密团队密钥
            String decryptedKey = decryptWithMasterKey(keyEntity.get().getEncryptedKey());

            log.debug("✅ 团队密钥获取成功: teamId={}", teamId);
            return decryptedKey;

        } catch (Exception e) {
            log.error("❌ 团队密钥获取失败: teamId={}, userId={}", teamId, userId, e);
            throw new RuntimeException("团队密钥获取失败", e);
        }
    }

    /**
     * 轮换团队密钥（生成新版本密钥）
     * 
     * @param teamId 团队ID
     * @param userId 操作用户ID
     * @return 新密钥ID
     */
    public Long rotateTeamKey(Long teamId, Long userId) {
        try {
            log.info("🔄 开始轮换团队密钥: teamId={}, userId={}", teamId, userId);

            // 1. 验证用户权限（只有团队管理员可以轮换密钥）
            if (!teamMemberService.isTeamAdmin(teamId, userId)) {
                throw new SecurityException("只有团队管理员可以轮换密钥");
            }

            // 2. 将当前密钥设为非活跃
            teamEncryptionKeyRepository.deactivateTeamKeys(teamId);

            // 3. 生成新密钥
            Long newKeyId = generateTeamKey(teamId, userId);

            log.info("✅ 团队密钥轮换成功: teamId={}, newKeyId={}", teamId, newKeyId);
            return newKeyId;

        } catch (Exception e) {
            log.error("❌ 团队密钥轮换失败: teamId={}", teamId, e);
            throw new RuntimeException("团队密钥轮换失败", e);
        }
    }

    /**
     * 检查团队是否有可用密钥，如果没有则自动生成
     * 
     * @param teamId 团队ID
     * @param userId 用户ID
     * @return 是否成功确保密钥存在
     */
    public boolean ensureTeamKey(Long teamId, Long userId) {
        try {
            if (!teamEncryptionKeyRepository.existsActiveKeyForTeam(teamId)) {
                log.info("🔧 团队无可用密钥，自动生成: teamId={}", teamId);
                generateTeamKey(teamId, userId);
                return true;
            }
            return true;
        } catch (Exception e) {
            log.error("❌ 确保团队密钥失败: teamId={}", teamId, e);
            return false;
        }
    }

    /**
     * 使用主密钥加密数据
     */
    private String encryptWithMasterKey(String data) throws Exception {
        // 确保主密钥长度为32字节（256位）
        byte[] keyBytes = masterKeyString.getBytes(StandardCharsets.UTF_8);
        if (keyBytes.length < 32) {
            byte[] paddedKey = new byte[32];
            System.arraycopy(keyBytes, 0, paddedKey, 0, Math.min(keyBytes.length, 32));
            keyBytes = paddedKey;
        } else if (keyBytes.length > 32) {
            byte[] truncatedKey = new byte[32];
            System.arraycopy(keyBytes, 0, truncatedKey, 0, 32);
            keyBytes = truncatedKey;
        }

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        
        // 生成随机IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        new SecureRandom().nextBytes(iv);
        
        GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, parameterSpec);

        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        
        // 将IV和加密数据组合
        byte[] encryptedWithIv = new byte[GCM_IV_LENGTH + encryptedData.length];
        System.arraycopy(iv, 0, encryptedWithIv, 0, GCM_IV_LENGTH);
        System.arraycopy(encryptedData, 0, encryptedWithIv, GCM_IV_LENGTH, encryptedData.length);

        return Base64.getEncoder().encodeToString(encryptedWithIv);
    }

    /**
     * 使用主密钥解密数据
     */
    private String decryptWithMasterKey(String encryptedData) throws Exception {
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        
        // 分离IV和加密数据
        byte[] iv = new byte[GCM_IV_LENGTH];
        byte[] encrypted = new byte[decodedData.length - GCM_IV_LENGTH];
        
        System.arraycopy(decodedData, 0, iv, 0, GCM_IV_LENGTH);
        System.arraycopy(decodedData, GCM_IV_LENGTH, encrypted, 0, encrypted.length);

        // 确保主密钥长度为32字节（256位）
        byte[] keyBytes = masterKeyString.getBytes(StandardCharsets.UTF_8);
        if (keyBytes.length < 32) {
            byte[] paddedKey = new byte[32];
            System.arraycopy(keyBytes, 0, paddedKey, 0, Math.min(keyBytes.length, 32));
            keyBytes = paddedKey;
        } else if (keyBytes.length > 32) {
            byte[] truncatedKey = new byte[32];
            System.arraycopy(keyBytes, 0, truncatedKey, 0, 32);
            keyBytes = truncatedKey;
        }

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, parameterSpec);

        byte[] decryptedData = cipher.doFinal(encrypted);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * 获取团队的下一个密钥版本号
     */
    private int getNextKeyVersion(Long teamId) {
        return teamEncryptionKeyRepository.findMaxVersionByTeamId(teamId)
                .map(version -> version + 1)
                .orElse(1);
    }

    /**
     * 检查加密服务健康状态
     */
    public boolean isHealthy() {
        try {
            // 测试主密钥加密解密
            String testData = "health_check_" + System.currentTimeMillis();
            String encrypted = encryptWithMasterKey(testData);
            String decrypted = decryptWithMasterKey(encrypted);
            
            return testData.equals(decrypted);
        } catch (Exception e) {
            log.error("❌ 加密服务健康检查失败", e);
            return false;
        }
    }
}
